import multiprocessing
import sys
from multiprocessing import Queue

from PyQt6.QtGui import QIcon, QFont
from PyQt6.QtWidgets import (QWidget, QVBoxLayout, QApplication, QHBoxLayout, QLabel, QButtonGroup, QCheckBox,
                             QLineEdit, QPushButton, QComboBox, QGroupBox, QPlainTextEdit, QFileDialog, QMessageBox,
                             QProgressBar)
from src.utils.global_variable import logging
from src.checkurl.multiprocess_operation import *
from src.constants.ui_constants import *


class UI(QWidget):
    def __init__(self):
        super().__init__()
        self.script_path = os.getcwd()
        self.worker = None  # 用于多进程工作
        self.result_path = None
        self.range_detection_group = QGroupBox()  # 范围检测模式group
        self.label_start_url_line = QLineEdit()  # 起始地址输入框
        self.label_end_url_line = QLineEdit()  # 结束地址输入框
        # 创建队列用于与子进程通信
        self.queue = Queue()

        # 创建信号发射器对象
        self.signal_emitter = SignalEmitter(self.queue)
        self.signal_emitter.message_received.connect(self.update_text_browser)  # 打印信息处理
        self.signal_emitter.progress_updated.connect(self.update_progress)  # 进度条显示刷新
        self.signal_emitter.task_completed.connect(self.task_finished)  # 进度条完成
        self.signal_emitter.result_opened.connect(self.open_result)  # 任务完成后提示打开文件
        self.signal_emitter.show_range_detection_warning.connect(self.show_warning)

        # 创建主垂直布局
        self.main_VBoxlayout = QVBoxLayout()

        # hbox_choose_mode 检测模式选择
        self.hbox_choose_mode = QHBoxLayout()
        self.choose_mode_label = QLabel(Label.CHOOSE_MODE)
        # 创建按钮组并设置互斥
        self.button_group = QButtonGroup()
        self.button_group.setExclusive(True)  # 设置为互斥模式
        # 创建多个checkbox用于选择模式
        self.checkbox1 = QCheckBox(CheckBox.MARKDOWN)  # MD文件检测
        self.checkbox1.setChecked(True)
        self.checkbox2 = QCheckBox(CheckBox.HUAWEI)  # 现网链接检测
        self.checkbox3 = QCheckBox(CheckBox.HUAWEI_TEST)  # 测试网链接检测
        self.checkbox4 = QCheckBox(CheckBox.README_MD)  # README.md文件检测
        self.button_group.addButton(self.checkbox1)
        self.button_group.addButton(self.checkbox2)
        self.button_group.addButton(self.checkbox3)
        self.button_group.addButton(self.checkbox4)
        self.button_group.buttonToggled.connect(self.uncheck_others)
        self.hbox_choose_mode.addWidget(self.choose_mode_label)
        self.hbox_choose_mode.addWidget(self.checkbox1)
        self.hbox_choose_mode.addWidget(self.checkbox2)
        self.hbox_choose_mode.addWidget(self.checkbox3)
        self.hbox_choose_mode.addWidget(self.checkbox4)

        # 功能布局
        self.function_VBoxlayout = QVBoxLayout()
        # 初始化不同布局
        self.init_check_md_layout()
        self.init_check_huawei_layout()
        self.init_check_huawei_test_layout()
        self.init_check_readme_layout()

        # 默认隐藏其他未勾选布局
        self.huawei_group.hide()
        self.huawei_test_group.hide()
        self.read_group.hide()

        # print_area_hbox打印区域
        self.print_area_hbox = QHBoxLayout()
        self.text_browser = QPlainTextEdit()
        self.text_browser.textChanged.connect(self.scroll_to_bottom)
        self.text_browser.setReadOnly(True)
        self.text_browser.setFont(QFont('Microsoft YaHei', 8))
        self.print_area_hbox.addWidget(self.text_browser)

        # 进度条组件
        self.progress_bar = QProgressBar()
        self.progress_bar.setValue(0)
        self.progress_bar.setVisible(False)

        # 将layout加入到主布局中
        self.main_VBoxlayout.addLayout(self.hbox_choose_mode)
        self.main_VBoxlayout.addLayout(self.function_VBoxlayout)
        self.main_VBoxlayout.addLayout(self.print_area_hbox)
        self.main_VBoxlayout.addWidget(self.progress_bar)

        # 窗口设置
        self.setGeometry(*Window.GEOMETRY)
        self.setWindowTitle(Window.WINDOW_TITLE)
        self.setWindowIcon(QIcon(Window.WINDOW_ICON))
        self.setLayout(self.main_VBoxlayout)
        self.show()

    def update_text_browser(self, message):
        """多进程信号传递后刷新"""
        if message.endswith('Process is finished'):
            self.worker = None
        self.text_browser.appendPlainText(f'{message}')
        if 'Failed' in message:
            logging.error(message)
        else:
            logging.info(message)

    def update_progress(self, value):
        """更新进度"""
        self.progress_bar.setValue(value)

    def task_finished(self):
        """任务完成"""
        self.progress_bar.setValue(100)
        self.progress_bar.hide()

    def open_result(self):
        """任务完成后提示打开结果文件"""
        msg = QMessageBox()
        msg.setIcon(QMessageBox.Icon.Information)
        msg.setWindowTitle("任务完成")
        msg.setText("任务已完成！")
        msg.setInformativeText(f"是否打开结果文件: {self.result_path}?")
        msg.setStandardButtons(
            QMessageBox.StandardButton.Yes |
            QMessageBox.StandardButton.No
        )

        response = msg.exec()
        if response == QMessageBox.StandardButton.Yes:
            self.open_excel_file(self.result_path)
        # 点击No会自动关闭对话框

    def open_excel_file(self, file_path):
        """使用系统默认程序打开Excel文件"""
        try:
            if sys.platform == "win32":
                os.startfile(file_path)
            elif sys.platform == "darwin":
                subprocess.run(["open", file_path])
            else:
                subprocess.run(["xdg-open", file_path])
        except Exception as e:
            QMessageBox.critical(self, "错误", f"无法打开文件:\n{e}")

    def scroll_to_bottom(self):
        """打印区域保持滚动条置于最底位置"""
        # 使用单次定时器确保在布局更新后执行
        QTimer.singleShot(0, lambda: self.text_browser.verticalScrollBar().setValue(
            self.text_browser.verticalScrollBar().maximum()
        ))

    def show_warning(self):
        warning = QMessageBox()
        warning.setWindowTitle('错误！！！')
        warning.setText('输入的检测范围有误，请确认')
        warning.exec()

    def uncheck_others(self, button, checked):
        """根据选择checkbox加载不同布局"""
        if checked:
            mode = button.text()
            self.update_text_browser(f'当前检测模式：{mode}')
            if self.checkbox1.isChecked():
                self.md_group.show()
                self.huawei_group.hide()
                self.huawei_test_group.hide()
                self.read_group.hide()
            elif self.checkbox2.isChecked():
                self.md_group.hide()
                self.huawei_group.show()
                self.huawei_test_group.hide()
                self.read_group.hide()
            elif self.checkbox3.isChecked():
                self.md_group.hide()
                self.huawei_group.hide()
                self.huawei_test_group.show()
                self.read_group.hide()
            elif self.checkbox4.isChecked():
                self.md_group.hide()
                self.huawei_group.hide()
                self.huawei_test_group.hide()
                self.read_group.show()

    def init_check_md_layout(self):
        """初始化md文档检测布局"""
        self.md_group = QGroupBox(GroupBoxTitle.MD)
        hbox = QHBoxLayout()
        label = QLabel(Label.CHECK_MD_PATH_LABEL)
        # 目录展示栏
        self.path_display = QLineEdit()
        self.path_display.setFont(QFont('Microsoft YaHei', 8))
        # 选择目录按钮
        choose_dir_button = QPushButton(ButtonTitle.CHOOSE_PATH)
        choose_dir_button.clicked.connect(self.select_file)
        hbox.addWidget(label)
        hbox.addWidget(self.path_display)
        hbox.addWidget(choose_dir_button)

        hbox2 = QHBoxLayout()
        self.combo1 = QComboBox()
        test_mode = [ComboTitle.TEST_MODE_HEADLESS_TRUE, ComboTitle.TEST_MODE_HEADLESS_FALSE]
        self.combo1.addItems(test_mode)
        # 开始检测按钮
        start_button1 = QPushButton(ButtonTitle.START_CHECK)
        start_button1.clicked.connect(self.start_check_md)
        hbox2.addWidget(self.combo1, stretch=3)
        hbox2.addWidget(start_button1, stretch=1)
        vbox = QVBoxLayout()
        vbox.addLayout(hbox)
        vbox.addLayout(hbox2)
        self.md_group.setLayout(vbox)

        self.function_VBoxlayout.addWidget(self.md_group)

    def init_check_huawei_layout(self):
        """初始化现网检测布局"""
        self.huawei_group = QGroupBox(GroupBoxTitle.HUAWEI)
        hbox = QHBoxLayout()
        label1 = QLabel(Label.LANGUAGE)
        self.combo2 = QComboBox()  # 语言选择
        language_items = [ComboTitle.LANGUAGE_CN, ComboTitle.LANGUAGE_EN]
        self.combo2.addItems(language_items)
        label2 = QLabel(Label.TEST_MODE)
        self.combo3 = QComboBox()  # 检测模式选择
        test_mode = [ComboTitle.TEST_MODE_HEADLESS_TRUE, ComboTitle.TEST_MODE_HEADLESS_FALSE,
                     ComboTitle.TEST_MODE_RANGE_DETECTION]
        self.combo3.currentIndexChanged.connect(self.on_combobox_changed)
        self.combo3.addItems(test_mode)
        label3 = QLabel(Label.PRODUCT)
        self.combo4 = QComboBox()  # 产品类型选择
        products = [ComboTitle.GUIDES, ComboTitle.API, ComboTitle.BEST_PRACTICES, ComboTitle.FAQ, ComboTitle.CODELABS,
                    ComboTitle.OVERVIEW_ALL_VERSION, ComboTitle.ARCHITECTURE, ComboTitle.ATOMIC_GUIDES,
                    ComboTitle.ATOMIC_API, ComboTitle.ATOMIC_FAQ, ComboTitle.ATOMIC_ASCF,
                    ComboTitle.ATOMIC_OVERVIEW_ALL_VERSION, ]
        self.combo4.addItems(products)
        # 开始检测按钮
        start_button2 = QPushButton(ButtonTitle.START_CHECK)
        start_button2.clicked.connect(self.start_check_huawei)
        hbox.addWidget(label1, stretch=1)
        hbox.addWidget(self.combo2, stretch=2)
        hbox.addWidget(label2, stretch=1)
        hbox.addWidget(self.combo3, stretch=2)
        hbox.addWidget(label3, stretch=1)
        hbox.addWidget(self.combo4, stretch=2)
        hbox.addWidget(start_button2, stretch=2)

        self.huawei_group.setLayout(hbox)
        self.function_VBoxlayout.addWidget(self.huawei_group)

        # 范围检测group
        self.range_detection_group = QGroupBox(GroupBoxTitle.RANGE_DETECTION)
        self.range_detection_group.hide()
        hbox_range_detection1 = QHBoxLayout()
        label_start_url = QLabel(Label.START_URL)
        hbox_range_detection1.addWidget(label_start_url)
        hbox_range_detection1.addWidget(self.label_start_url_line)

        hbox_range_detection2 = QHBoxLayout()
        label_end_url = QLabel(Label.END_URL)
        hbox_range_detection2.addWidget(label_end_url)
        hbox_range_detection2.addWidget(self.label_end_url_line)

        vbox_range_detection = QVBoxLayout()
        vbox_range_detection.addLayout(hbox_range_detection1)
        vbox_range_detection.addLayout(hbox_range_detection2)
        self.range_detection_group.setLayout(vbox_range_detection)

        self.function_VBoxlayout.addWidget(self.range_detection_group)

    def on_combobox_changed(self, index):
        # 当选项索引变化时调用
        self.range_detection_group.show() if index == 2 else self.range_detection_group.hide()

    def init_check_huawei_test_layout(self):
        """初始化现网检测布局"""
        self.huawei_test_group = QGroupBox(GroupBoxTitle.HUAWEI_TEST)
        hbox = QHBoxLayout()
        label1 = QLabel(Label.LANGUAGE)
        self.combo5 = QComboBox()  # 语言选择
        language_items = [ComboTitle.LANGUAGE_CN, ComboTitle.LANGUAGE_EN]
        self.combo5.addItems(language_items)
        label2 = QLabel(Label.TEST_MODE)
        self.combo6 = QComboBox()  # 检测模式选择
        test_mode = [ComboTitle.TEST_MODE_HEADLESS_TRUE, ComboTitle.TEST_MODE_HEADLESS_FALSE]
        self.combo6.addItems(test_mode)
        label3 = QLabel(Label.PRODUCT)
        self.combo7 = QComboBox()  # 产品类型选择
        products = [ComboTitle.GUIDES, ComboTitle.API, ComboTitle.BEST_PRACTICES, ComboTitle.FAQ,
                    ComboTitle.OVERVIEW_ALL_VERSION]
        self.combo7.addItems(products)
        # 开始检测按钮
        start_button3 = QPushButton(ButtonTitle.START_CHECK)
        start_button3.clicked.connect(self.start_check_huawei_test)

        hbox.addWidget(label1, stretch=1)
        hbox.addWidget(self.combo5, stretch=2)
        hbox.addWidget(label2, stretch=1)
        hbox.addWidget(self.combo6, stretch=2)
        hbox.addWidget(label3, stretch=1)
        hbox.addWidget(self.combo7, stretch=2)
        hbox.addWidget(start_button3, stretch=2)

        # 设置代理
        hbox_proxy = QHBoxLayout()
        label_proxy = QLabel(Label.PROXY)
        label_proxy_username = QLabel("用户名:")
        self.proxy_username_input = QLineEdit()
        self.proxy_username_input.setPlaceholderText("代理用户名(可选)")

        label_proxy_password = QLabel("密码:")
        self.proxy_password_input = QLineEdit()
        self.proxy_password_input.setPlaceholderText("代理密码(可选)")
        self.proxy_password_input.setEchoMode(QLineEdit.EchoMode.Password)
        hbox_proxy.addWidget(label_proxy)
        hbox_proxy.addWidget(label_proxy_username)
        hbox_proxy.addWidget(self.proxy_username_input)
        hbox_proxy.addWidget(label_proxy_password)
        hbox_proxy.addWidget(self.proxy_password_input)

        vbox = QVBoxLayout()
        vbox.addLayout(hbox)
        vbox.addLayout(hbox_proxy)

        self.huawei_test_group.setLayout(vbox)
        self.function_VBoxlayout.addWidget(self.huawei_test_group)

    def init_check_readme_layout(self):
        """初始化readme.md文档检测布局"""
        self.read_group = QGroupBox(GroupBoxTitle.README)
        hbox = QHBoxLayout()
        label = QLabel(Label.CHECK_README_PATH_LABEL)
        # 目录展示栏
        self.path_display = QLineEdit()
        self.path_display.setFont(QFont('Microsoft YaHei', 8))
        # 选择目录按钮
        choose_dir_button = QPushButton(ButtonTitle.CHOOSE_PATH)
        choose_dir_button.clicked.connect(self.select_dir)
        hbox.addWidget(label)
        hbox.addWidget(self.path_display)
        hbox.addWidget(choose_dir_button)

        hbox2 = QHBoxLayout()
        self.combo1 = QComboBox()
        test_mode = [ComboTitle.TEST_MODE_HEADLESS_TRUE, ComboTitle.TEST_MODE_HEADLESS_FALSE]
        self.combo1.addItems(test_mode)
        # 开始检测按钮
        start_button1 = QPushButton(ButtonTitle.START_CHECK)
        start_button1.clicked.connect(self.start_check_readme)
        hbox2.addWidget(self.combo1, stretch=3)
        hbox2.addWidget(start_button1, stretch=1)
        vbox = QVBoxLayout()
        vbox.addLayout(hbox)
        vbox.addLayout(hbox2)
        self.read_group.setLayout(vbox)

        self.function_VBoxlayout.addWidget(self.read_group)

    def select_file(self):
        """选择待检测的zip文件"""
        while True:
            file_path, _ = QFileDialog.getOpenFileName(self, '请选择待检测文件')
            if file_path.endswith('zip'):
                self.text_browser.appendPlainText(f'已选择目标文件：{file_path}')
                logging.info(f'已选择目标文件：{file_path}')
                self.path_display.setText(file_path)
                self.text_browser.appendPlainText(f'解压文件：{file_path}')
                logging.info(f'解压文件：{file_path}')
                dir_path = '/'.join(file_path.split('/')[:-1]) + f'/chick_result/{file_path.split("/")[-1][:-4]}'
                self.to_be_check_path = dir_path
                self.decompress_zip(file_path, dir_path)
                self.result_path = dir_path + '/超链接.xlsx'
                break
            elif file_path == '':
                break
            else:
                QMessageBox.information(self, '文件类型错误', '待检测文件应以.zip格式结尾，请重新选择')
                logging.warning('待检测文件应以.zip格式结尾，请重新选择')

    def select_dir(self):
        """选择待检测的目录"""
        dir_path = QFileDialog.getExistingDirectory(self, '请选择待检测目录')
        if dir_path != '':
            self.text_browser.appendPlainText(f'已选择目标目录：{dir_path}')
            logging.info(f'已选择目标目录：{dir_path}')
            self.path_display.setText(dir_path)
            self.to_be_check_path = dir_path
            self.result_path = dir_path + '/超链接.xls'

    def decompress_zip(self, file_path, dir_path):
        """解压待检测文件"""
        if not self.worker:
            # 开启其他进程解压文件，避免阻塞主进程
            self.worker = DecompressZipProcess(self.queue, file_path, dir_path)
            self.worker.start()
        else:
            self.text_browser.appendPlainText(f'已存在其他进程工作中，等待其他进程工作完毕：{self.worker.__class__}')

    def start_check_md(self):
        self.progress_bar.setVisible(True)
        if not self.worker:
            # 开启其他进程检查链接，避免阻塞主线程
            check_dir = self.path_display.text()
            if check_dir != '':
                print(self.combo1.currentText())
                test_mode = True if self.combo1.currentText() == '有头模式' else False
                self.worker = CheckUrlProcessMD(self.queue, self.to_be_check_path, self.script_path, test_mode)
                self.worker.start()
            else:
                self.text_browser.appendPlainText(f'请先选择待检测文件')
                logging.warning(f'请先选择待检测文件')
        else:
            self.text_browser.appendPlainText(f'已存在其他进程工作中，等待其他进程工作完毕：{self.worker.__class__}')
            logging.warning(f'已存在其他进程工作中，等待其他进程工作完毕：{self.worker.__class__}')

    def start_check_readme(self):
        self.progress_bar.setVisible(True)
        if not self.worker:
            # 开启其他进程检查链接，避免阻塞主线程
            check_dir = self.path_display.text()
            if check_dir != '':
                test_mode = True if self.combo1.currentText() == '有头模式' else False
                self.worker = CheckUrlProcessReadme(self.queue, self.to_be_check_path, self.script_path, test_mode)
                self.worker.start()
            else:
                self.text_browser.appendPlainText(f'请先选择待检测文件')
                logging.warning(f'请先选择待检测文件')
        else:
            self.text_browser.appendPlainText(f'已存在其他进程工作中，等待其他进程工作完毕：{self.worker.__class__}')

    def start_check_huawei(self):
        self.progress_bar.setVisible(True)
        if not self.worker:
            # 开启其他进程检查链接，避免阻塞主线程
            test_mode = True if self.combo3.currentText() == '有头模式' or '范围检测' else False
            language = 'cn' if self.combo2.currentText() == '中文' else 'en'
            product = self.combo4.currentText()
            self.worker = CheckUrlProcessHuawei(self.queue, test_mode, language, product)
            if self.combo3.currentIndex() == 2:
                self.worker.start_url = self.label_start_url_line.text()
                self.worker.end_url = self.label_end_url_line.text()
            self.worker.start()
        else:
            self.text_browser.appendPlainText(f'已存在其他进程工作中，等待其他进程工作完毕：{self.worker.__class__}')
            logging.warning(f'已存在其他进程工作中，等待其他进程工作完毕：{self.worker.__class__}')

    def start_check_huawei_test(self):
        self.progress_bar.setVisible(True)
        if not self.worker:
            # 开启其他进程检查链接，避免阻塞主线程
            test_mode = True if self.combo6.currentText() == '有头模式' else False
            language = 'cn' if self.combo5.currentText() == '中文' else 'en'
            product = self.combo7.currentText()
            proxies = create_proxies(self.proxy_username_input.text(), self.proxy_password_input.text())
            self.worker = CheckUrlProcessHuaweiTest(self.queue, test_mode, language, product, proxies)
            self.worker.start()
        else:
            self.text_browser.appendPlainText(f'已存在其他进程工作中，等待其他进程工作完毕：{self.worker.__class__}')
            logging.warning(f'已存在其他进程工作中，等待其他进程工作完毕：{self.worker.__class__}')


def create_proxies(proxy_username, proxy_password, proxy_host='proxy.huawei.com', proxy_port=8080):
    # 对密码中的特殊字符进行URL编码
    import urllib.parse
    encoded_password = urllib.parse.quote(proxy_password, safe='')

    proxies = {
        'http': f'http://{proxy_username}:{encoded_password}@{proxy_host}:{proxy_port}',
        'https': f'http://{proxy_username}:{encoded_password}@{proxy_host}:{proxy_port}'
    }
    return proxies


def ui_main():
    # 在Windows打包exe时，多进程需要这样处理
    multiprocessing.freeze_support()

    app = QApplication(sys.argv)
    # 创建一个全局字体
    font = QFont('Arial', 14)
    # 将这个字体设置未应用程序的全局字体
    app.setFont(font)
    ui = UI()
    logging.info('初始化UI界面')
    sys.exit(app.exec())


if __name__ == '__main__':
    ui_main()
